package cn.wolfcode.web.controller;

import cn.wolfcode.common.domain.UserInfo;
import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.common.web.anno.RequireLogin;
import cn.wolfcode.domain.OrderInfo;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMessage;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.UserUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.ConcurrentHashMap;


@RestController
@RequestMapping("/order")
@Slf4j
public class OrderInfoController {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private IOrderInfoService orderInfoService;
    //本地标识
    public static final ConcurrentHashMap<Long, Boolean> local_flag = new ConcurrentHashMap<>();


    @RequestMapping("/find")
    public Result<OrderInfo> find(String orderNo, HttpServletRequest request) {
        if (StringUtils.isBlank(orderNo)) {
            throw new BusinessException(SeckillCodeMsg.PARAM_ERROR);
        }
        OrderInfo orderInfo = orderInfoService.find(orderNo);
        if (orderInfo == null) {
            throw new BusinessException(SeckillCodeMsg.PARAM_ERROR);
        }
        UserInfo userInfo = UserUtil.getUser(redisTemplate, request.getHeader("token"));
        if (!userInfo.getPhone().equals(orderInfo.getUserId())) {
            throw new BusinessException(SeckillCodeMsg.PARAM_ERROR);
        }
        return Result.success(orderInfo);
    }

    //Request URL: http://localhost:9000/seckill/order/doSeckill
    //seckillId: 6  time: 10

    @RequestMapping("/doSeckill")
    //1.判斷是否有登錄
    @RequireLogin
    public Result<String> doSeckill(Long seckillId, int time, HttpServletRequest request) {

        //2.做参数非空校验
        if (StringUtils.isBlank(String.valueOf(seckillId)) || StringUtils.isBlank(String.valueOf(time))) {
            throw new BusinessException(SeckillCodeMsg.PARAM_ERROR);
        }

        //3.判断它是否在活动时间内
        //SeckillProductVo seckillProductVo = seckillProductService.find(time, seckillId);
        //boolean isOver = DateUtil.isLegalTime(seckillProductVo.getStartDate(), time);
        //if (!isOver) {
        //    throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        //}

        //如果本地标识为true,那么直接抛出异常,不让他去访问我们的redis
        Boolean isFlag = local_flag.get(seckillId);
        if (isFlag != null && isFlag) {
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }

        //4.判断库存是否足够 (这个可以不用要了,上面利用redis的原子性递减,最多只有10个请求过来,所以库存不可能小于0了)
        //if (seckillProductVo.getStockCount() <= 0) {
        //    throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        //}

        //5.判断是否有重复下单
        /**
         * String   seckillOrder:13088889999:11       true
         * Hash     seckillHash        seckillId:phone      true
         * Set      seckillSet:timInitSeckillProductListJobe    seckillId:phone      isMember
         */
        //userInfo用户信息的key 是怎么存的,userToken:token
        String token = request.getHeader("token");
        UserInfo userInfo = UserUtil.getUser(redisTemplate, token);
        Boolean isExists = redisTemplate.opsForSet().isMember(SeckillRedisKey.SECKILL_ORDER_SET
                .getRealKey(String.valueOf(time)), seckillId + ":" + userInfo.getPhone());
        if (isExists) {
            throw new BusinessException(SeckillCodeMsg.REPEAT_SECKILL);
        }

        //原子性递减控制秒杀请求
        //使用redis控制人数,防止并发访问数据库 减少redis预库存
        Long preStock = redisTemplate.opsForHash().increment(SeckillRedisKey.SECKILL_STOCK_COUNT_HASH.getRealKey(String.valueOf(time))
                , String.valueOf(seckillId), -1);
        if (preStock < 0) {
            //进来说明秒杀商品预库存小于0了,给本地标识设置为true,减少redis操作,节省网络资源
            local_flag.put(seckillId, true);
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }

        //6.秒杀业务逻辑
        //String orderNo = orderInfoService.doSeckill(seckillId, time, userInfo.getPhone());

        //创建消息封装对象
        OrderMessage orderMessage = new OrderMessage();
        orderMessage.setTime(time);
        orderMessage.setSeckillId(seckillId);
        orderMessage.setToken(token);
        orderMessage.setUserPhone(userInfo.getPhone());
        //发送同步消息
        rocketMQTemplate.sendOneWay(MQConstant.ORDER_PEDDING_TOPIC, orderMessage);//订单队列
        return Result.success("正在抢购中,请稍后...");
    }
}
